// Copyright 2007-2008 Rory Plaire (codekaizen@gmail.com)
//
// Based initially on JAMA : A Java Matrix Package by 
// National Institute of Standards and Technology (NIST) 
// and The MathWorks, a public-domain work.

using System;
using NPack.Interfaces;

namespace NPack
{
    /// <summary>
    /// A matrix used to model systems numerically.
    /// </summary>
    /// <typeparam name="T">Type of element in the matrix.</typeparam>
    public class NumericalMatrix<T> : Matrix<T>, INumericalMatrix<T>
        where T : IEquatable<T>, IComparable<T>, IComputable<T>, IConvertible, IFormattable
    {
        /// <summary>
        /// Creates a new <see cref="NumericalMatrix{T}"/>.
        /// </summary>
        /// <param name="rows">Rows in the matrix.</param>
        /// <param name="cols">Columns in the matrix.</param>
        public NumericalMatrix(Int32 rows, Int32 cols)
            : base(MatrixFormat.ColumnMajor, rows, cols) {}

        /// <summary>
        /// Creates a new <see cref="NumericalMatrix{T}"/>.
        /// </summary>
        /// <param name="elements">Elements to use for the matrix.</param>
        public NumericalMatrix(T[][] elements)
            : base(MatrixFormat.ColumnMajor, elements) {}

        /// <summary>
        /// Creates a new <see cref="NumericalMatrix{T}"/> with a specific storage format.
        /// </summary>
        /// <param name="format">Storage format for the matrix, either row-major or column-major.</param>
        /// <param name="elements">Elements to use for the matrix.</param>
        public NumericalMatrix(MatrixFormat format, T[][] elements)
            : base(format, elements) {}

        #region INumericalMatrix<T> Members

        /// <summary>
        /// Returns a matrix which is the solution to the 
        /// <paramref name="b">given matrix</paramref>, if one exists.
        /// </summary>
        /// <param name="b">Matrix to solve this linear system for.</param>
        /// <returns>
        /// The solution, x, to the equation <c>Ax = B</c>, where the 
        /// <see cref="NumericalMatrix{T}"/> is the "A" matrix and the <paramref name="b"/>
        /// parameter is B.
        /// </returns>
        public IMatrix<T> Solve(IMatrix<T> b)
        {
            return MatrixProcessor<T>.Instance.Operations.Solve(this, b);
        }

        /// <summary>
        /// Gets the 1 norm for the matrix.
        /// </summary>
        /// <value>
        /// The maximum column sum.
        /// </value>
        public Double Norm1
        {
            get { return MatrixProcessor<T>.Instance.Operations.OneNorm(this); }
        }

        /// <summary>
        /// Gets the infinity (or max) norm for the matrix.
        /// </summary>
        /// <value>
        /// The maximum row sum.
        /// </value>
        public Double InfinityNorm
        {
            get { return MatrixProcessor<T>.Instance.Operations.InfinityNorm(this); }
        }

        /// <summary>
        /// Gets the Frobenius norm for the matrix.
        /// </summary>
        /// <value>
        /// The square root of sum of squares of all elements.
        /// </value>
        public Double FrobeniusNorm
        {
            get { return MatrixProcessor<T>.Instance.Operations.FrobeniusNorm(this); }
        }

        /// <summary>
        /// Gets the trace of the matrix.
        /// </summary>
        /// <returns>
        /// Sum of the diagonal elements.
        /// </returns>
        public Double Trace
        {
            get { return MatrixProcessor<T>.Instance.Operations.Trace(this); }
        }

        #endregion

        #region IComputable<IMatrix<T>> Members

        public new IMatrix<T> Abs()
        {
            throw new NotImplementedException();
        }

        public new IMatrix<T> Set(double value)
        {
            throw new NotImplementedException();
        }

        public IMatrix<T> SetFrom(IMatrix<T> value)
        {
            throw new NotImplementedException();
        }

        #endregion

        #region IDivisible<IMatrix<T>> Members

        public IMatrix<T> Divide(IMatrix<T> b)
        {
            throw new NotImplementedException();
        }

        #endregion

        #region IExponential<IMatrix<T>> Members

        public new IMatrix<T> Power(double exponent)
        {
            throw new NotImplementedException();
        }

        public new IMatrix<T> Sqrt()
        {
            throw new NotImplementedException();
        }

        public new IMatrix<T> Log(double newBase)
        {
            throw new NotImplementedException();
        }

        IMatrix<T> IExponential<IMatrix<T>>.Log()
        {
            throw new NotImplementedException();
        }

        public new IMatrix<T> Exp()
        {
            throw new NotImplementedException();
        }

        #endregion
    }
}